package org.canaan.quartz;

import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.core.Constants;
import org.springframework.util.Assert;

import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;

/**
 @Author Canaan
 @Date 2018/3/16 */
public class CronTriggerBuilder {

    private static final Constants constants = new Constants(CronTrigger.class);
    private String    name;
    private String    group;
    private JobDetail jobDetail;
    private JobDataMap jobDataMap = new JobDataMap();
    private Date startTime;
    private long startDelay = 0L;
    private String   cronExpression;
    private TimeZone timeZone;
    private String   calendarName;
    private int      priority;
    private int      misfireInstruction;
    private String   description;


    public CronTriggerBuilder setName(String name) {
        this.name = name;
        return this;
    }

    public CronTriggerBuilder setGroup(String group) {
        this.group = group;
        return this;
    }

    public CronTriggerBuilder setJobDetail(JobDetail jobDetail) {
        this.jobDetail = jobDetail;
        return this;
    }

    public JobDataMap getJobDataMap() {
        return this.jobDataMap;
    }

    public CronTriggerBuilder setJobDataMap(JobDataMap jobDataMap) {
        this.jobDataMap = jobDataMap;
        return this;
    }

    public CronTriggerBuilder setJobDataAsMap(Map<String, ?> jobDataAsMap) {
        this.jobDataMap.putAll(jobDataAsMap);
        return this;
    }

    public CronTriggerBuilder setStartTime(Date startTime) {
        this.startTime = startTime;
        return this;
    }

    public CronTriggerBuilder setStartDelay(long startDelay) {
        Assert.isTrue(startDelay >= 0L, "Start delay cannot be negative");
        this.startDelay = startDelay;
        return this;
    }

    public CronTriggerBuilder setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
        return this;
    }

    public CronTriggerBuilder setTimeZone(TimeZone timeZone) {
        this.timeZone = timeZone;
        return this;
    }

    public CronTriggerBuilder setCalendarName(String calendarName) {
        this.calendarName = calendarName;
        return this;
    }

    public CronTriggerBuilder setPriority(int priority) {
        this.priority = priority;
        return this;
    }

    public CronTriggerBuilder setMisfireInstruction(int misfireInstruction) {
        this.misfireInstruction = misfireInstruction;
        return this;
    }

    public CronTriggerBuilder setMisfireInstructionName(String constantName) {
        this.misfireInstruction = constants.asNumber(constantName).intValue();
        return this;
    }

    public CronTriggerBuilder setDescription(String description) {
        this.description = description;
        return this;
    }


    public CronTrigger build() throws ParseException {

        if (this.group == null) {
            this.group = "DEFAULT";
        }

        if (this.jobDetail != null) {
            this.jobDataMap.put("jobDetail", this.jobDetail);
        }

        if (this.startDelay > 0L || this.startTime == null) {
            this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
        }

        if (this.timeZone == null) {
            this.timeZone = TimeZone.getDefault();
        }

        CronTriggerImpl cti = new CronTriggerImpl();
        cti.setName(this.name);
        cti.setGroup(this.group);
        if (this.jobDetail != null) {
            cti.setJobKey(this.jobDetail.getKey());
        }

        cti.setJobDataMap(this.jobDataMap);
        cti.setStartTime(this.startTime);
        cti.setCronExpression(this.cronExpression);
        cti.setTimeZone(this.timeZone);
        cti.setCalendarName(this.calendarName);
        cti.setPriority(this.priority);
        cti.setMisfireInstruction(this.misfireInstruction);
        cti.setDescription(this.description);
        return cti;
    }

}
